package com.nowcoder.community.service.impl;

import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.FollowService;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FollowServiceImpl implements FollowService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    @Override
    public void follow(int userId, int entityType, int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
                operations.multi();
                operations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
                operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
                operations.exec();
                return null;
            }
        });
    }

    @Override
    public void unfollow(int userId, int entityType, int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
                operations.multi();
                operations.opsForZSet().remove(followeeKey, entityId);
                operations.opsForZSet().remove(followerKey, userId);
                operations.exec();
                return null;
            }
        });
    }

    /**
     * 应为是redis的查询
     * 所以不需要开启事务
     * @param userId
     * @param entityType
     * @return
     */
    @Override
    public long findFolloweeCount(int userId, int entityType) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    @Override
    public long findFollowerCount(int entityType, int entityId) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    @Override
    public boolean isFollowed(int userId, int entityType, int entityId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
    }

    @Override
    public List<Map<String, Object>> findFolloweeList(int userId, int entityId, int limit, int offset) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityId);
        // 查询不需要开启事务
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        if(targetIds == null || targetIds.isEmpty()) {
            return null;
        }
        List<Map<String, Object>> followeeList = new ArrayList<>();
        for(Integer id : targetIds) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.findUserById(id);
            map.put("user", user);
            // 查询关注时间
            Double millisTime = redisTemplate.opsForZSet().score(followeeKey, id);
            map.put("followTime", new Date(millisTime.longValue()));
            followeeList.add(map);
        }
        return followeeList;
    }

    /**
     * 一般业务情况下
     * entityType = 3 -> 用户实体类型
     * entityId就是被关注用户的userId
     * @param entityType
     * @param entityId
     * @param limit
     * @param offset
     * @return
     */
    @Override
    public List<Map<String, Object>> findFollowerList(int entityType, int entityId, int limit, int offset) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        // 查询粉丝列表
        // 返回的是一个有序的Set
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
        if(targetIds == null || targetIds.isEmpty()) {
            return null;
        }
        List<Map<String, Object>> followerList = new ArrayList<>();
        for(Integer id : targetIds) {
            Map<String, Object> map = new HashMap<>();
            // 查询粉丝用户实体
            User user = userService.findUserById(id);
            map.put("user", user);
            // 查询关注时间
            Double millisTime = redisTemplate.opsForZSet().score(followerKey, id);
            map.put("followTime", new Date(millisTime.longValue()));
            followerList.add(map);
        }
        return followerList;
    }

}
